use futures_util::stream::StreamExt;
use std::collections::HashMap;
use std::convert::Infallible;
use std::io::Read;
use std::ptr::null;
use bincode::{deserialize, serialize};
use futures_util::TryStreamExt;
use serde_json::json;
use tokio::io::AsyncWriteExt;
use crate::db::find_user_by_account;
use crate::warp_error::AuthError;
use chat_core::jwt::{sign, verify};
use chat_core::user::User;
use warp::{Filter, Stream};
use warp::multipart::{FormData, FormOptions, Part};
use crate::db_init::{files, users};
use mem_data::onLineUsers;
use uuid::Uuid;
use crate::mem_data;

const WARP_APIS_PREFIX: &str = "api";
const X_AUTH_TOKEN: &str = "X-Auth-ACCOUNT-Token";
const X_AUTH_ACCOUNT: &str = "X-Auth-ACCOUNT";
// 用户认证
fn auth() -> impl Filter<Extract = (String,), Error = warp::Rejection> + Clone  {
    warp::any()
        .and(warp::header::<String>(X_AUTH_TOKEN))
        .and(warp::header::<String>(X_AUTH_ACCOUNT))
        .and_then(|token: String, account: String| async move {
            if !token.is_empty() {
                let valid = verify(&token, &account);
                log::info!("token: {} valid: {}", token, valid);
                if !valid {
                    return Err(warp::reject::custom(AuthError{reason: "token not valid".to_string()}))
                }
                return Ok(account);
            }
            Err(warp::reject::custom(AuthError{reason: "token not valid".to_string()}))
        })
}
// 用户登录
pub fn login() -> impl Filter<Extract = (String,), Error = warp::Rejection> + Clone  {
    warp::post().and(warp::path(WARP_APIS_PREFIX))
        .and(warp::path("login"))
        .and(warp::body::json())
        .and_then(|json: serde_json::Value| async move {
            let user = serde_json::from_value::<User>(json).unwrap();
            match find_user_by_account(&user.account.clone()) {
                Some(u) => {
                    if u.password == user.password {
                        Ok(sign(&u.account.clone()))
                    }else {
                        Err(warp::reject::custom(AuthError{reason: "password error".to_string()}))
                    }
                }
                None => Err(warp::reject::custom(AuthError{reason: "account not found".to_string()}))
            }
        })
}
// 用户注册
pub fn register() -> impl Filter<Extract = (warp::reply::Json,), Error = warp::Rejection> + Clone  {
    warp::post().and(warp::path(WARP_APIS_PREFIX))
        .and(warp::path("register"))
        .and(warp::body::json())
        .and_then(|json: serde_json::Value| async move {
            let user = serde_json::from_value::<User>(json).unwrap();
            match find_user_by_account(&user.account.clone()) {
                Some(_) => Err(warp::reject::custom(AuthError{reason: "account already exists".to_string()})),
                None => {
                    let register_result = users.lock().unwrap().insert(&user.account.clone(),serialize(&user).unwrap()).is_ok();
                    let json_result = json!({
                        "success": register_result,
                    });
                    Ok(warp::reply::json(&json_result))
                }
            }
        })
}
// 获取在线用户列表
pub fn online_users() -> impl Filter<Extract = (warp::reply::Json,), Error = warp::Rejection> + Clone  {
    warp::post().and(warp::path(WARP_APIS_PREFIX))
        .and(warp::path("onlineUsers"))
        .and(auth())
        .and_then(|request_account: String| async move {
            let mut online_users_account = Vec::new();
            onLineUsers.lock().await.iter().for_each(|(account, _)| {
                log::info!("online user: {} request account: {}", account,request_account);
                if *account != request_account {
                    online_users_account.push(account.clone());
                }
            });
            let json_result = json!(online_users_account);
            Ok::<warp::reply::Json, warp::Rejection>(warp::reply::json(&json_result))
        })
}
// 搜索用户
pub fn search_users() -> impl Filter<Extract = (warp::reply::Json,), Error = warp::Rejection> + Clone  {
    warp::post().and(warp::path(WARP_APIS_PREFIX))
        .and(warp::path("searchUsers"))
        .and(auth())
        .and(warp::body::json())
        .and_then(|request_account: String, json: serde_json::Value| async move {
            log::info!("request account: {} search text: {:?}", request_account,json);
            let search_text = serde_json::from_value::<HashMap<String, String>>(json).unwrap();
            let search_text = search_text.get("searchText").unwrap().to_string();
            let mut result_users = Vec::new();
            users.lock().unwrap().iter().for_each(|data| {
                match data {
                    Ok((_, user_data)) => {
                        let user: User = deserialize(&user_data).unwrap();
                        if user.account.contains(&search_text) {
                            result_users.push(user);
                        }
                    }
                    Err(e) => {
                        log::error!("error: {}", e);
                    }   
                };
            });
            let json_result = json!(result_users);
            Ok::<warp::reply::Json, warp::Rejection>(warp::reply::json(&json_result))
        })
}

// 上传文件
pub fn upload_file() -> impl Filter<Extract = (warp::reply::Json,), Error = warp::Rejection> + Clone {
    warp::multipart::form()
        .and(warp::path(WARP_APIS_PREFIX))
        .and(warp::path("uploadFile"))
        .and(auth())
        .and_then(|form:FormData,request_account: String| async move {
            log::info!("upload file start request account: {}", request_account);
            let flag:(String,String) = form.and_then(|field| async move {
                let file_unique_name = Uuid::new_v4().to_string();
                let file_unique_name_clone = file_unique_name.clone();
                let name = field.name();
                let file_name = field.filename().unwrap().to_owned();
                if name == "file" {
                    //let file_name = field.filename().unwrap();
                    // 确保上传目录存在
                    tokio::fs::create_dir_all("./uploads").await.unwrap();
                    // 将文件内容保存到磁盘
                    let file_path = format!("./uploads/{}", file_name);
                    let mut file = tokio::fs::File::create(&file_path).await.unwrap();
                    let mut stream = field.stream();
                    while let Some(chunk) = stream.next().await {
                        let mut chunk = chunk.unwrap();
                        file.write_all_buf(&mut chunk).await.unwrap();
                    }
                    file.flush().await.unwrap();
                    files.lock().unwrap().insert(file_unique_name, file_path.as_bytes()).unwrap();
                }
                Ok((file_unique_name_clone,file_name))
            }).try_collect().await.unwrap();
            let json_result = json!({
                "fileUniqueName": flag.0,
                "fileName": flag.1,
            });
            log::info!("upload file success: {:?}", json_result);
            Ok::<warp::reply::Json, warp::Rejection>(warp::reply::json(&json_result))
        })
}
